/*******************************************************************************
 * Copyright (c) 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.action;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.ISubmitResult;
import net.sourceforge.perforce.core.api.IWhereResult;
import net.sourceforge.perforce.core.resources.IChangelist;
import net.sourceforge.perforce.core.syncinfo.ResourceSyncInfo;
import net.sourceforge.perforce.ui.dialogs.ChangeSpecDialog;
import net.sourceforge.perforce.ui.internal.Policy;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.IAction;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

/**
  * @version 	$Revision: 77 $
  * @author		<a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class SubmitAction extends PerforceAction
{
	// ------------------------------------------------------------------------------ Public Methods
	
	/** @see IActionDelegate#run(IAction) */
	public void run(IAction action)
	{
		final IChangelist[] changelists = getSelectedChangelists();				
		Policy.assertTrue(changelists.length == 1);
		
		ChangeSpecDialog dialog = null;
		try
		{
			dialog = ChangeSpecDialog.newInstance(getShell(), changelists[0]);
		}
		catch (PerforceException e)
		{
			handle(e);
			return;
		}
		
		if (dialog.open() == ChangeSpecDialog.OK)
		{
			final String changeSpecString = dialog.getChangeSpecString();

			run(new WorkspaceModifyOperation()
			{
				protected void execute(IProgressMonitor monitor)
					throws CoreException, InvocationTargetException
				{
					monitor.beginTask("", 1000);
					
					try
					{
						ISubmitResult[] result = new ISubmitResult[0];
						try
						{
							result = changelists[0].getServer().submit(changeSpecString);
							monitor.worked(500);
						}
						catch (PerforceException e)
						{
							throw new InvocationTargetException(e);
						}
	
						// Refresh Workspace
						IFile[] files = new IFile[result.length];					
						IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
						for (int i = 0, length = result.length; i < length; i++)
						{
							IWhereResult whereResult =
								changelists[0].getServer().where(result[i].getDepotFilename());
								
							// Refresh local file
							files[i] = root.getFileForLocation(
								new Path(whereResult.getLocalFilename()));
								
							if (result[i].isRefreshed())
							{
								files[i].refreshLocal(IResource.DEPTH_ZERO, monitor);
							}							
						}
						
						// Refresh Resource States
						refreshResourceStates(changelists[0].getServer(), files);
						
						// Refresh PendingChangelistView
						PerforceCorePlugin.getPlugin().broadcastChangelistStateChanges(changelists);						
					}
					catch (PerforceException e)
					{
						throw new InvocationTargetException(e);
					}
					finally
					{
						monitor.done();
					}
				}
			}, PROGRESS_DIALOG);
		}
	}
	
	// --------------------------------------------------------------------------- Protected Methods

	/** @see TeamAction#isEnabled() */
	protected boolean isEnabled()
		throws PerforceException
	{
		IChangelist[] changelists = getSelectedChangelists();
		if (changelists.length != 1)
			return false;
			
		IPerforceServer server = changelists[0].getServer();
		if (!(server.getClient().equals(changelists[0].getClientName())))
		{
			return false;
		}
			
		return true;
	}
	
	// ----------------------------------------------------------------------------- Private Methods
	
	/** Returns an array of all selected IChangelist objects.
	  * 
	  * @return array of selected changelists. 
	  */
	private IChangelist[] getSelectedChangelists()
	{
		ArrayList resources = null;
		if (!getSelection().isEmpty())
		{
			resources = new ArrayList();
			for (Iterator elements = getSelection().iterator(); elements.hasNext();)
			{
				Object next = elements.next();
				
				if (next instanceof IChangelist)
				{
					resources.add(next);
					continue;
				}
				else
				if (next instanceof IAdaptable)
				{
					IAdaptable a = (IAdaptable) next;
					Object adapter = a.getAdapter(IChangelist.class);
					if (adapter instanceof IChangelist)
					{
						resources.add(adapter);
						continue;
					}
				}
			}
		}
		
		if (resources != null && !resources.isEmpty())
		{
			
			return (IChangelist[]) resources.toArray(new IChangelist[resources.size()]);
		}
		
		return new IChangelist[0];
	}
	
	/** Called to update the resource sync infos of the given resources.
	  *
	  * @param server the perforce server.
	  * @param resources the changed resources. 
	  */
	private void refreshResourceStates(IPerforceServer server, IResource[] resources) 
	{
		PerforceCorePlugin.getSynchronizer().beginOperation(null);
		try
		{			
			for (int i = 0; i < resources.length; i++)
			{
				if (resources[i].getType() == IResource.FILE)
				{
					ResourceSyncInfo[] syncInfo =
						server.fstat(resources[i].getLocation().toOSString(), null);
					Policy.assertTrue(syncInfo.length == 1);
					PerforceCorePlugin.getSynchronizer().setResourceSync(resources[i], syncInfo[0]);
				}
			}
		}
		catch (PerforceException e)
		{
			PerforceCorePlugin.log(e.getStatus());
		}
		finally
		{
			try
			{
				PerforceCorePlugin.getSynchronizer().endOperation(null);
			}
			catch (PerforceException e)
			{
				PerforceCorePlugin.log(e.getStatus());
			}
		}
	}
	
}
